---
slug: /extending/secrets
description: "Learn how to use secrets in Dagger"
---

# Secrets

Dagger has first-class support for "secrets", such as passwords, API keys, SSH keys and so on. These secrets can be securely used in Dagger functions without exposing them in plaintext logs, writing them into the filesystem of containers you're building, or inserting them into the cache.

Here is an example, which uses a secret in a Dagger function chain:

```shell
export API_TOKEN="guessme"
```

<Tabs groupId="language" queryString="sdk">
<TabItem value="System shell">
```shell
dagger <<'EOF'
container |
  from alpine:latest |
  with-secret-variable MY_SECRET env://API_TOKEN |
  with-exec -- sh -c 'echo this is the secret: $MY_SECRET' |
  stdout
EOF
```
</TabItem>
<TabItem value="Dagger Shell">
```shell title="First type 'dagger' for interactive mode."
container |
  from alpine:latest |
  with-secret-variable MY_SECRET env://API_TOKEN |
  with-exec -- sh -c 'echo this is the secret: $MY_SECRET' |
  stdout
```
</TabItem>
<TabItem value="Dagger CLI">
```shell
dagger core container \
  from --address=alpine:latest \
  with-secret-variable --name="MY_SECRET" --secret="env://API_TOKEN" \
  with-exec --args="sh","-c",'echo this is the secret: $MY_SECRET' \
  stdout
```
</TabItem>
<TabItem value="go" label="Go">
```go file=./snippets/secrets/go/main.go
```
</TabItem>
<TabItem value="python" label="Python">
```python file=./snippets/secrets/python/main.py
```
</TabItem>
<TabItem value="typescript" label="TypeScript">
```typescript file=./snippets/secrets/typescript/index.ts
```
</TabItem>
<TabItem value="php" label="PHP">
```php file=./snippets/secrets/php/src/MyModule.php
```
</TabItem>
</Tabs>

[Secret arguments](./arguments.mdx#secret-arguments) can be sourced from multiple providers: the host environment, the host filesystem, the result of host command execution, and external secret managers [1Password](https://1password.com/) and [Vault](https://www.hashicorp.com/products/vault).

## Caching

When a `Secret` is included in other operations, the layer cache entries for those operations will be based on the plaintext value of the secret. If the same operation is run with a secret with the same plaintext value, that operation may be cached rather than re-executed. In the above example, the secret is specified as `env://API_TOKEN`, so the cache for the `with-exec` will be based on the plaintext value of the secret. If two clients execute the container and have the same `API_TOKEN` environment variable value, they may share layer cache entries for the container. However, if two clients have different values for the `API_TOKEN` environment variable, the `with-exec` will not share cache entries, even though both clients specify the secret as `env://API_TOKEN`.

In some cases, users may desire that operations share layer cache entries even if the secret plaintext value is different. For example, a secret may often rotate in plaintext value but not be meaningfully different; in these cases, it should still be possible to reuse the cache for operations that include that secret.

For these use cases, the optional `cacheKey` argument to `Secret` construction can be used to specify the "cache key" of the secret. Secrets that share the same `cacheKey` will be considered equivalent when checking cache of operations that include them, even if their plaintext value differs. See [the cookbook](../../cookbook/secrets.mdx#customize-secret-caching-behavior) for example usage.

## Security considerations

- Dagger automatically scrubs secrets from its various logs and output streams. This ensures that sensitive data does not leak - for example, in the event of a crash.
- Secret plaintext should be handled securely within your Dagger workflow. For example, you should not write secret plaintext to a file, as it could then be stored in the Dagger cache.
- Secrets are scoped by default to the modules they're defined in. To share a secret across modules, you must intentionally pass a reference to it via constructor or function arguments.
